﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using SemenQuest.Models;
using AgentEventArgs = SemenQuest.AgentController.AgentEventArgs;

namespace SemenQuest
{
    public partial class Main : Form
    {
        private Panel SimulationWindow { get; set; }
        private class MyPanel : Panel
        {
            public MyPanel()
            {
                this.DoubleBuffered = true;
                this.SetStyle(
                    ControlStyles.UserPaint |
                    ControlStyles.AllPaintingInWmPaint |
                    ControlStyles.OptimizedDoubleBuffer,
                    true);
                this.UpdateStyles();
                this.Dock = DockStyle.Fill;
                this.Margin = new Padding(0);
            }
        }

        public Main()
        {
            SimulationWindow = new MyPanel();
            SimulationWindow.BorderStyle = BorderStyle.Fixed3D;
            SimulationWindow.BackColor = Properties.Settings.Default.EnviromentBackgroundColor;
            this.Controls.Add(SimulationWindow);
            InitializeComponent();
            TransparencyKey = Color.Magenta;//.FromArgb(255, 0, 128);
            this.SetStyle(
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.AllPaintingInWmPaint |
                ControlStyles.UserPaint,
                true);

            this.UpdateStyles();

            Thread.CurrentThread.Name = "Main";
            StatisticsController.Initialize();
            SettingsController.Initialize();
            AgentController.Initialize();
            AgentController.AgentStateChanged += AgentController_AgentStateChanged;


            string version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
            Text += String.Format(" - v. {0}", version);
            SettingsController.EnviromentSettingChanged += EnviromentSettingsChanged;
            this.Resize += Main_Resize;
            SpawnTimer.Start();
        }

        private void EnviromentSettingsChanged(String setting, Object value)
        {
            switch (setting)
            {
                case "EnviromentMaxSemenAlive":
                case "EnviromentMaxEggAlive":
                    // Get agentType
                    String name = setting
                        .Remove(setting.Length - 5)
                        .Remove(0, 13);
                    Agent.AgentTypes agentType = (Agent.AgentTypes)Enum.Parse(typeof(Agent.AgentTypes), name);
                    // Get agents
                    List<Agent> agents = AgentController.GetAgentCount().Where(x => x.AgentType == agentType).ToList();
                    //Get new value
                    Int32 Value = (Int32)Properties.Settings.Default.GetType().GetProperty(setting).GetValue(Properties.Settings.Default);
                    //Remove surplus of agents
                    while (agents.Count > (Int32)Value)
                    {
                        AgentController.KillAgent(agents[0]);
                        agents.RemoveAt(0);
                    }
                    break;

                case "EnviromentBackgroundColor":
                    Invoke(new MethodInvoker(delegate()
                        {
                            SimulationWindow.BackColor = (Color)value;
                        }));
                    break;

                case "EnviromentSpawnRate":
                    Invoke(new MethodInvoker(delegate()
                    {
                        SpawnTimer.Interval = (Int32)value;
                        SpawnTimer.Start();
                    }));
                    break;

                default:
                    break;
            }
        }
        private void AgentController_AgentStateChanged(Agent agent, AgentEventArgs e)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new AgentController.AgentHandler(AgentController_AgentStateChanged), agent, e);
                return;
            }
            String additional;
            switch (e.AdditionalInfo)
            {
                case AgentEventArgs.AdditionalInfos.Spawned:
                    additional = " spawned!";
                    break;
                case AgentEventArgs.AdditionalInfos.AgentControllerKill:
                    additional = " was killed by user!";
                    break;
                case AgentEventArgs.AdditionalInfos.LifeTimeEnded:
                    additional = "'s life ended!";
                    break;
                case AgentEventArgs.AdditionalInfos.WonTheLottery:
                    additional = " impregnated an egg!";
                    break;
                default:
                    additional = " died!";
                    break;
            }
            StatusLabel.Text = agent.AgentType + " " + agent.Name + additional;
        }

        private void SpawnTimer_Tick(Object sender, EventArgs e)
        {
            Int32 number = Properties.Settings.Default.EnviromentMaxSemenAlive;
            if (AgentController.GetAgentCount(Agent.AgentTypes.Semen) < Properties.Settings.Default.EnviromentMaxSemenAlive)
            {
                Agent semen = AgentController.NewAgent(Agent.AgentTypes.Semen);
                semen.Parent = SimulationWindow;
                semen.RunAgent(true);
            }

            number = Properties.Settings.Default.EnviromentMaxEggAlive;
            if (AgentController.GetAgentCount(Agent.AgentTypes.Egg) < Properties.Settings.Default.EnviromentMaxEggAlive)
            {
                Agent egg = AgentController.NewAgent(Agent.AgentTypes.Egg);
                egg.Parent = SimulationWindow;
                egg.RunAgent(true);
            }
        }

        private void Main_Resize(Object sender, EventArgs e)
        {
            List<Agent> Agents = AgentController.GetAgentCount();
            if (Agents != null)
            {
                foreach (Agent agent in Agents)
                {
                    if (agent.Location.X < 0 ||
                        agent.Location.Y < 0 ||
                        agent.Location.X + agent.Width > SimulationWindow.Width ||
                        agent.Location.Y + agent.Height > SimulationWindow.Height)
                    {
                        AgentController.KillAgent(agent);
                    }
                }
            }
        }
        private void Main_FormClosing(Object sender, FormClosingEventArgs e)
        {
            AgentController.KillAllAgents();
        }
    }
}
